The Beginner’s Guide to Linux Kernel Module, Raspberry Pi and LED Matrix
| #include <linux/init.h> | |
| #include <linux/module.h> | |
| #include <linux/kthread.h> | |
| #include <linux/delay.h> | |
| #include <linux/gpio.h> | |
| MODULE_LICENSE("GPL"); | |
| /* GPIO */ | |
| #define A1 17 // 0 | |
| #define A2 18 // 1 | |
| #define A3 27 // 2 | |
| #define OE 22 // 3 | |
| #define LE 23 // 4 | |
| #define SDI 24 // 5 | |
| #define CLK 25 // 6 | |
| #define LINES 8 | |
| #define PER_LINE 12 | |
| static u8 pix_screen[LINES][PER_LINE] = { | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| { | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| 0b00000000,0b00000000,0b00000000,0b00000000, | |
| }, | |
| }; | |
| void pix_line(u8 row){ | |
| gpio_set_value(A1, !(row & 0b00000001)); | |
| gpio_set_value(A2, !(row & 0b00000010)); | |
| gpio_set_value(A3, !(row & 0b00000100)); | |
| } | |
| void pix_dot(int x, int y, int r, int g, int b) { | |
| uint8_t l,p,t; | |
| if(y % 2){ | |
| x = (x + 16); | |
| } | |
| y = (y / 2) - ((y / 2) % 1); | |
| l = x / 8; | |
| p = 7 - x % 8; | |
| t = pix_screen[y][l]; | |
| //printf("line:%i, l:%i, p:%i, t:%i\n", y,l,p,t); | |
| if(r) { | |
| t |= 1 << p; | |
| }else{ | |
| t &= ~(1 << p); | |
| } | |
| pix_screen[y][l] = t; | |
| l = x / 8 + 4; | |
| p = 7 - x % 8; | |
| t = pix_screen[y][l]; | |
| if(g) { | |
| t |= 1 << p; | |
| }else{ | |
| t &= ~(1 << p); | |
| } | |
| pix_screen[y][l] = t; | |
| l = x / 8 + 8; | |
| p = 7 - x % 8; | |
| t = pix_screen[y][l]; | |
| if(b) { | |
| t |= 1 << p; | |
| }else{ | |
| t &= ~(1 << p); | |
| } | |
| pix_screen[y][l] = t; | |
| } | |
| void pix_gpio_init(void){ | |
| printk(KERN_INFO "PIX: starting gpio..."); | |
| gpio_request(A1, "A1"); | |
| gpio_request(A2, "A2"); | |
| gpio_request(A3, "A3"); | |
| gpio_request(OE, "OE"); | |
| gpio_request(LE, "LE"); | |
| gpio_request(SDI, "SDI"); | |
| gpio_request(CLK, "CLK"); | |
| gpio_direction_output(A1, 0); | |
| gpio_direction_output(A2, 0); | |
| gpio_direction_output(A3, 0); | |
| gpio_direction_output(OE, 1); | |
| gpio_direction_output(LE, 0); | |
| gpio_direction_output(SDI, 0); | |
| gpio_direction_output(CLK, 0); | |
| printk(KERN_INFO "PIX: starting gpio done."); | |
| } | |
| void pix_gpio_exit(void){ | |
| printk(KERN_INFO "PIX: stopping gpio..."); | |
| gpio_free(A1); | |
| gpio_free(A2); | |
| gpio_free(A3); | |
| gpio_free(OE); | |
| gpio_free(LE); | |
| gpio_free(SDI); | |
| gpio_free(CLK); | |
| printk(KERN_INFO "PIX: stopping gpio done."); | |
| } | |
| /* SYSFS */ | |
| static struct kobject *pix_kobject; | |
| static ssize_t set_pix(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { | |
| u8 x = 0; | |
| u8 y = 0; | |
| u8 r = 0; | |
| u8 g = 0; | |
| u8 b = 0; | |
| sscanf(buff, "%hhd %hhd %hhd %hhd %hhd", &x, &y, &r, &g, &b); | |
| pix_dot(x,y,r,g,b); | |
| // printk(KERN_INFO "PIX: %d %d %d %d %d", x,y,r,g,b); | |
| return count; | |
| } | |
| static struct kobj_attribute pix_attribute =__ATTR(dot, (S_IWUSR | S_IRUGO), NULL, set_pix); | |
| void pix_sysfs_init(void){ | |
| printk(KERN_INFO "PIX: starting sysfs..."); | |
| pix_kobject = kobject_create_and_add("pix", NULL); | |
| if (sysfs_create_file(pix_kobject, &pix_attribute.attr)) { | |
| pr_debug("failed to create pix sysfs!\n"); | |
| } | |
| printk(KERN_INFO "PIX: starting sysfs done."); | |
| } | |
| void pix_sysfs_exit(void){ | |
| printk(KERN_INFO "PIX: stopping sysfs..."); | |
| kobject_put(pix_kobject); | |
| printk(KERN_INFO "PIX: stopping sysfs done."); | |
| } | |
| /* THREAD */ | |
| #define THREAD_PRIORITY 45 | |
| #define THREAD_NAME "pix" | |
| struct task_struct *task; | |
| int pix_thread(void *data){ | |
| u8 line, pos, bit; | |
| struct task_struct *TSK; | |
| struct sched_param PARAM = { .sched_priority = MAX_RT_PRIO - 50 }; | |
| //struct sched_param PARAM = { .sched_priority = DEFAULT_PRIO }; | |
| TSK = current; | |
| PARAM.sched_priority = THREAD_PRIORITY; | |
| sched_setscheduler(TSK, SCHED_FIFO, &PARAM); | |
| while(1) { | |
| for(line = 0; line < LINES; line++) { | |
| pix_line(line); | |
| for(pos = 0; pos < PER_LINE; pos++) { | |
| for (bit = 0; bit < 8; bit++) { | |
| gpio_set_value(SDI, !!(pix_screen[line][pos] & (1 << (7 - bit)))); | |
| gpio_set_value(CLK, 1); | |
| gpio_set_value(CLK, 0); | |
| } | |
| } | |
| gpio_set_value(LE, 1); | |
| gpio_set_value(LE, 0); | |
| gpio_set_value(OE, 0); | |
| usleep_range(2000, 2000); | |
| gpio_set_value(OE, 1); | |
| } | |
| if (kthread_should_stop()) break; | |
| } | |
| return 0; | |
| } | |
| void pix_thread_init(void){ | |
| printk(KERN_INFO "PIX: starting thread..."); | |
| task = kthread_run(pix_thread, NULL, THREAD_NAME); | |
| printk(KERN_INFO "PIX: starting thread done."); | |
| } | |
| void pix_thread_exit(void){ | |
| printk(KERN_INFO "PIX: stopping thread..."); | |
| kthread_stop(task); | |
| printk(KERN_INFO "PIX: stopping thread done."); | |
| } | |
| /* MODULE */ | |
| static int __init pix_init(void){ | |
| printk(KERN_INFO "PIX: staring..."); | |
| pix_gpio_init(); | |
| pix_thread_init(); | |
| pix_sysfs_init(); | |
| printk(KERN_INFO "PIX: staring done."); | |
| return 0; | |
| } | |
| static void __exit pix_exit(void){ | |
| printk(KERN_INFO "PIX: stopping..."); | |
| pix_sysfs_exit(); | |
| pix_thread_exit(); | |
| pix_gpio_exit(); | |
| printk(KERN_INFO "PIX: stopping done."); | |
| } | |
| module_init(pix_init); | |
| module_exit(pix_exit); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment